#ifndef PROPERTY_IMPL_H
#define PROPERTY_IMPL_H
#include "type_helper.h"
#include <map>
#include <vector>
#include <iostream>
#include <boost/type_traits/is_integral.hpp>
#include <boost/limits.hpp>
#include <limits>

namespace vpm 
{
	namespace utils
	{
		namespace detail
		{



template <class KeyT,class INTEGRAL_KEY = KeyTraitType<boost::is_integral<KeyT>::value >  > 
class PropertyImpl
{
	public:
		typedef std::vector<boost::any> Properties; 
		typedef std::vector<KeyT> MandatoryProperties;

#ifdef WIN32

		PropertyImpl(KeyT maxIndex =512):m_properties(maxIndex)
#else 
		PropertyImpl(KeyT maxIndex =
				(std::numeric_limits<KeyT>::max()< 512?std::numeric_limits<KeyT>::max():512))
			:m_properties(maxIndex) //TODO when key type is unsigned char , 
			//maybe it's a bug, so we need a template method to get the max of this type
#endif //
		{
			
		}

		template <class T> 
			bool set_property( const KeyT n , T  v)
			{
				if ((Properties::size_type ) n >= m_properties.size() )
				{
					printf("out of range , max index is %d\n",m_properties.size()-1);
					return false;
				}

				if ( !m_properties[n].empty() )
				{
					//check the type;
					if (m_properties[n].type() != typeid(v))
					{
						std::cout<< "Can't update a property with another type value!\n";
						return false;
					}
				}
				m_properties[n] = TypeSetter<T>()(v);
				return true; 
			}

		template <class T> 
			T get_property(const KeyT  n)
			{
				if ((Properties::size_type ) n < m_properties.size() && !m_properties[n].empty())
				{					
					return TypeGetter<T>()(m_properties[n]);
				}
				return T(); 
			}

		void set_mandatory_property(const KeyT k)
		{
			m_mandatoryProperties.push_back(k);
		}

		bool check_mandatory_properties()
		{
			bool result = false; 
			for(typename MandatoryProperties::iterator itr = m_mandatoryProperties.begin(); itr != m_mandatoryProperties.end(); ++itr)
			{
				if (m_properties[*itr].empty())
				{
					std::cout << "Property [" <<*itr<<"] not set."<<std::endl;
				}
			}
			return result;
		}

	private:
		Properties m_properties; 
		MandatoryProperties m_mandatoryProperties;
};

template<class KeyT >
class PropertyImpl<KeyT ,STRING_KEY >
{
	public:
		PropertyImpl()
		{
			
		}

		typedef std::map<KeyT,boost::any> Properties; 
		typedef std::vector<KeyT> MandatoryProperties;

		template <class T> 
			bool set_property( const KeyT & n , T  v)
			{
				typename Properties::iterator itr = m_properties.find(n);
				if (itr != m_properties.end())
				{
					//check the type;
					if (itr->second.type() != typeid(v))
					{
						std::cout<<"Can't update a string property with another type value!\n";
						return false;
					}
				}
				m_properties[n] = TypeSetter<T>()(v);
				return true; 
			}

		template <class T> 
			T get_property(const KeyT & n)
			{
				typename Properties::iterator itr = m_properties.find(n);

				if (itr != m_properties.end())
				{					
					return TypeGetter<T>()(itr->second);
				}
				return T(); 
			}

		void set_mandatory_properties(const KeyT &k)
		{
			m_mandatoryProperties.push_back(k);
		}

		bool check_mandatory()
		{
			bool result = false; 
			for(typename MandatoryProperties::iterator itr = m_mandatoryProperties.begin(); itr != m_mandatoryProperties.end(); ++itr)
			{
				if (m_properties[*itr].empty())
				{
					std::cout << "Property [" <<*itr<<"] not set."<<std::endl;
				}
			}
			return result;
		}
	private:
		Properties m_properties; 
		MandatoryProperties m_mandatoryProperties;
};

}
}
}

#endif // 
